package com.k.ums.aspectj;

import com.k.ums.annotations.DataSource;
import com.k.ums.datasource.DynamicDataSourceContextHolder;
import com.k.ums.enums.DataSourceType;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;

/**
 * @Description:
 * @Author: kt
 * @CreateTime: 2022/1/8
 */
@Component
@Aspect
public class DataSourceAspect {
    private static final String POINT_CUT_EXECUTION = "execution(* com.k.ums.service..*.*(..))";

    @Value("#{'${read.method}'.split(',')}")
    private List<String> readMethods;

    @Around(POINT_CUT_EXECUTION)
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        DataSourceType dataSourceType = this.getDataSourceType(((MethodSignature) joinPoint.getSignature()).getMethod());
        DynamicDataSourceContextHolder.set(dataSourceType);
        try {
            return joinPoint.proceed();
        } finally {
            DynamicDataSourceContextHolder.clear();
        }
    }

    private DataSourceType getDataSourceType(Method method) {
        DataSource dataSource = AnnotationUtils.findAnnotation(method, DataSource.class);
        if (dataSource != null) {
            return dataSource.value();
        } else {
            return getDataSourceType(method.getName());
        }
    }

    private DataSourceType getDataSourceType(String methodName) {
        return isReadMethod(methodName) ? DataSourceType.SALVE : DataSourceType.MASTER;
    }

    private boolean isReadMethod(String methodName) {
        return readMethods.stream().anyMatch(item -> methodName.startsWith(item));
    }
}
